﻿/*MyPhotoIndex Free Photo Organizer <www.myphotoindex.com>
  Copyright (C) <2006-2010>  <Asaf Yarkoni asaf@yarkoni.net>

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.*/
using System;
using System.Collections.Generic;
using System.Text;
using MyPhotoIndex.Interfaces.Plugins;
using MyPhotoIndex.Interfaces;
using System.Drawing;
using System.Windows.Forms;
using System.Threading;
using MyPhotoIndex.Interfaces.Imaging;
using MyPhotoIndex.ImageBank;
using MyPhotoIndex.Plugins.Utilities.FindDuplicates.Properties;
using MyPhotoIndex.Utilities;
using System.Collections.ObjectModel;

namespace MyPhotoIndex.Plugins.Utilities.FindDuplicates
{
    public class FindDuplicatesPlugin : IUtilityPlugin
    {
        static bool m_running = false;

        private IApplicationContext m_applicationContext;

        #region IPlugin Members

        public string Description
        {
            get { return "Find Duplicate images"; }
        }

        public bool Load(IApplicationContext applicationContext)
        {
            m_applicationContext = applicationContext;

            return true;
        }

        public string Name
        {
            get { return "Find duplicate photos"; }
        }

        public void Unload()
        {
            
        }

        #endregion

        #region IUtilityPlugin Members

        public void RegisterMenues(List<IPluginMenuInfo> pluginMenuInfoList)
        {
            PluginMenuInfo menuInfo = new PluginMenuInfo();
            menuInfo.MenuItemId = Guid.NewGuid();
            menuInfo.Name = "Find Duplicates";
            menuInfo.Icon = Resources.duplicates;
            menuInfo.MenuItemClick += new EventHandler<PluginMenuClickEventArgs>(menuInfo_MenuItemClick);
            menuInfo.MenuItemQueryState += new EventHandler<PluginMenuStateQueryEventArgs>(menuInfo_MenuItemQueryState);

            pluginMenuInfoList.Add(menuInfo);
        }

        public void ImageSelectionChanged(ReadOnlyCollection<int> selectedImages, SelectedImageInfo lastSelected)
        {
        }

        void menuInfo_MenuItemQueryState(object sender, PluginMenuStateQueryEventArgs e)
        {
            e.Enabled = (m_running == false);
        }

        void menuInfo_MenuItemClick(object sender, PluginMenuClickEventArgs e)
        {
            m_running = true;
            ThreadPool.QueueUserWorkItem(new WaitCallback(doSearch));
        }

        void doSearch(object state)
        {
            Dictionary<int, string> hashList = new Dictionary<int, string>();
            IImageData[] images = m_applicationContext.ImageCollection.ToArray();

            m_applicationContext.ProcessProgress.ProcessDescription = "Find Duplicate images";
            m_applicationContext.ProcessProgress.Maximum = images.Length;
            m_applicationContext.ProcessProgress.IsInfinite = false;
            m_applicationContext.ProcessProgress.Running = true;

            List<int> duplicateImages = new List<int>();
            foreach (IImageData imageData in images)
            {
                m_applicationContext.ProcessProgress.Value++;
                int[] duplicates = FindImageDuplicates(imageData, images, hashList);
                foreach (int id in duplicates)
                {
                    if (duplicateImages.Contains(id) == false)
                    {
                        duplicateImages.Add(id);
                    }
                }
            }

            string message = string.Empty;
            if (duplicateImages.Count > 0)
            {
                Storage.Instance.Filter(duplicateImages);
                message = "Found " + duplicateImages.Count.ToString() + " duplicate images";
            }
            else
            {
                message = "No duplicate images found in your index ";
            }

            m_applicationContext.ProcessProgress.Running = false;



            m_applicationContext.ProcessProgress.Alert(ProcessAlertType.Info, message, string.Empty, string.Empty);

            m_running = false;
        }

        private int[] FindImageDuplicates(IImageData imageData, IImageData[] images, Dictionary<int, string> hashList)
        {
            List<int> duplicateImages = new List<int>();

            string imageHash = GetImageComparableHash(imageData, hashList);
            if (string.IsNullOrEmpty(imageHash) == false)
            {
                foreach (IImageData otherImageData in images)
                {
                    if (otherImageData != imageData &&
                        otherImageData.FileExtention.CompareTo(imageData.FileExtention) == 0 &&
                        imageData.DateTaken.CompareTo(otherImageData.DateTaken) == 0)
                    {
                        string otherImageHash = GetImageComparableHash(otherImageData, hashList);
                        if (string.Compare(otherImageHash, imageHash) == 0)
                        {
                            duplicateImages.Add(imageData.Id);
                            duplicateImages.Add(otherImageData.Id);
                        }
                    }
                }
            }

            return duplicateImages.ToArray();
        }

        private string GetImageComparableHash(IImageData imageData, Dictionary<int, string> hashList)
        {
            string imageHash = string.Empty;
            if (hashList.TryGetValue(imageData.Id, out imageHash) == false)
            {
                try
                {
                    imageHash = imageData.FormatProvider.GetImageMediaSignature(imageData.FileName);
                    hashList.Add(imageData.Id, imageHash);
                }
                catch (Exception ex)
                {
                    Logger.Log(ex);
                }
            }

            return imageHash;
        }

 

        #endregion
    }
}
